import { NavBar, InfiniteScroll, Toast, Popup } from "antd-mobile";
import { useHistory, useParams } from "react-router-dom";
import classNames from "classnames";
import styles from "./index.module.scss";
import Icon from "@/components/Icon";
import CommentItem from "./components/CommentItem";
import CommentFooter from "./components/CommentFooter";
import { useInitialState } from "@/utils/use-initial-state";
import {
    addArticleComment,
    collectArticle,
    followAuthor,
    getArticleById,
    getArticleComments,
    getMoreArticleComments,
    likeArticle,
    likeComment,
    updateCommentCount,
} from "@/store/actions/article";
import DOMPurify from "dompurify";
import highlight from "highlight.js";
import "highlight.js/styles/github.css";
import { useEffect, useRef, useState } from "react";
import ContentLoader from "react-content-loader";
import { useDispatch } from "react-redux";
import NoneComment from "@/components/NoneComment";
import CommentInput from "./components/CommentInput";
import { ArtComment } from "@/types/data";
import Reply from "./components/Reply";
/**
 * 导航栏高度的常量
 */
enum CommentType {
    Article = "a",
    Comment = "c",
}
const NAV_BAR_HEIGTH = 45;
const Article = () => {
    const dispatch = useDispatch();
    const history = useHistory();
    // 获取路由参数
    const params = useParams<{ artId: string }>();
    // 表示文章是否加载中的状态
    const [loading, setLoading] = useState(true);
    // 创建文章可滚动区域的ref对象
    const wrapperRef = useRef<HTMLDivElement>(null);
    // 创建导航栏作者信息的ref对象
    const authorRef = useRef<HTMLDivElement>(null);
    // 控制导航栏中作者信息的展示和隐藏
    const [showNavAuthor, setShowNavAuthor] = useState(false);
    // 创建评论信息的DOM对象的 ref
    const commentRef = useRef<HTMLDivElement>(null);
    // 创建用来表示当前是否展示评论信息的ref
    const isShowComment = useRef(false);
    // 创建控制文章评论弹出层展示或隐藏的状态
    const [commentVisible, setCommentVisible] = useState(false);
    // 控制文章评论回复弹出层的展示或隐藏的状态
    // 获取文章详情
    const { detail, comments } = useInitialState(
        () => getArticleById(params.artId),
        "article",
        () => setLoading(false)
    );
    // 解构出文章详情数据：
    const {
        art_id,
        aut_id,
        // 是否点赞
        attitude,
        // 是否收藏
        is_collected,
        content,
        is_followed,
        aut_name,
        aut_photo,
        comm_count,
        like_count,
        pubdate,
        read_count,
        title,
    } = detail;
    // 文章详情 代码内容 高亮
    useEffect(() => {
        const dgHtmlDOM = document.querySelector(".dg-html");
        const codes = dgHtmlDOM?.querySelectorAll<HTMLElement>("pre code");
        // console.log(codes)
        if (codes && codes.length > 0) {
            codes.forEach((el) => {
                // 让每个 code 内容实现代码高亮
                highlight.highlightElement(el);
            });
            return;
        }

        highlight.configure({
            // 忽略警告
            ignoreUnescapedHTML: true,
        });

        // 直接找到所有的 pre 标签
        const pres = dgHtmlDOM?.querySelectorAll("pre");
        if (pres && pres.length > 0) {
            pres.forEach((el) => {
                highlight.highlightElement(el);
            });
        }
    }, [detail]);
    // 导航栏中展示作者信息
    useEffect(() => {
        if (loading) return;
        const wrapperDOM = wrapperRef.current!;
        // 节流
        let timer: any = null;
        const handleScroll = () => {
            let flag = true;
            if (flag) {
                timer = window.setInterval(() => {
                    const { bottom } =
                        authorRef.current!.getBoundingClientRect();
                    // 44 是 NavBar 的高度，因为 NavBar 会挡住页面内容，所以，此处需要减去它的高度
                    if (bottom - 44 <= 0) {
                        setShowNavAuthor(true);
                    } else {
                        setShowNavAuthor(false);
                    }
                    flag = true;
                }, 200);
            }
            flag = false;
        };
        wrapperDOM.addEventListener("scroll", handleScroll);
        return () => {
            wrapperDOM.removeEventListener("scroll", handleScroll);
            clearInterval(timer);
        };
    }, [loading]);
    // 展示 or 隐藏评论内容
    // 点击跳转到评论内容
    const onShowComment = () => {
        const wrapper = wrapperRef.current!;
        if (!wrapper) return;
        const comment = commentRef.current!;
        if (!comment) return;

        const commentTop = comment.getBoundingClientRect().top;

        if (!isShowComment.current) {
            // 还没有展示评论信息，此时，就展示评论信息
            window.scrollTo({
                // wrapper.scrollTop 表示已经滚动的距离
                top: commentTop - NAV_BAR_HEIGTH + wrapper.scrollTop,
                // 如果想要滚动时，带有动画效果，可以使用 smooth 即可
                behavior: "smooth",
            });
            isShowComment.current = true;
        } else {
            // 已经展示评论信息，此时，需要返回页面顶部
            window.scrollTo({ top: 0, behavior: "smooth" });
            isShowComment.current = false;
        }
    };
    // 处理关注
    const onFollow = () => {
        dispatch(followAuthor(params.artId, is_followed));
        Toast.show(is_followed ? "取消关注" : "已关注");
    };
    // 收藏 or 取消收藏 -- 文章
    const onCollected = async () => {
        await dispatch(collectArticle(art_id, is_collected));
        Toast.show(is_collected ? "取消收藏" : "已收藏");
    };
    // 点赞 或 取消点赞 -- 文章
    const onLike = async () => {
        await dispatch(likeArticle(art_id, attitude));
        Toast.show(attitude ? "取消点赞" : "已点赞");
    };

    // 第一次获取评论
    useEffect(() => {
        dispatch(getArticleComments(CommentType.Article, params.artId));
    }, [dispatch, params.artId]);
    const { last_id, end_id } = comments;
    // 是否有更多评论
    const hasMore = end_id !== last_id;
    // 以后每次：InfiniteScroll 加载评论数据
    const loadMoreComments = async () => {
        await dispatch(
            getMoreArticleComments(CommentType.Article, params.artId, last_id)
        );
    };
    // 评论弹层显示和隐藏
    const onCommentShow = () => setCommentVisible(true);
    const onCommentHide = () => setCommentVisible(false);
    // 对文章发表评论
    const onAddComment = async (content: string) => {
        await dispatch(addArticleComment(detail.art_id, content));
        // 关闭评论抽屉
        onCommentHide();
    };
    // 评论回复的弹出层需要的数据类型
    type CommentReply = {
        /**
         * 弹出层的展示或隐藏
         */
        visible: boolean;
        /**
         * 评论项内容
         */
        commentItem: ArtComment;
    };
    // 对评论点赞
    const onThumbsUp = async (id: string, is_liking: boolean) => {
        await dispatch(likeComment(id, is_liking));
    };
    // 回复评论
    const [commentReply, setCommentReply] = useState<CommentReply>({
        visible: false,
        commentItem: {} as ArtComment,
    });

    // 打开
    const onCommentReplyShow = (commentItem: ArtComment) => {
        setCommentReply({
            visible: true,
            commentItem,
        });
    };
    const onCloseReplyWithUpdate = (commentId: string, total: number) => {
        // 修改redux中的评论列表数据
        dispatch(updateCommentCount(commentId, total));
        onCommentReplyHide();
    };
    // 关闭
    const onCommentReplyHide = () =>
        setCommentReply({
            ...commentReply,
            visible: false,
        });
    // 加载loading效果
    if (loading) {
        return (
            // 根据当前页面结构，设计好的 loading 效果
            <ContentLoader
                speed={2}
                width={375}
                height={230}
                viewBox="0 0 375 230"
                backgroundColor="#f3f3f3"
                foregroundColor="#ecebeb">
                <rect x="16" y="8" rx="3" ry="3" width="340" height="10" />
                <rect x="16" y="26" rx="0" ry="0" width="70" height="6" />
                <rect x="96" y="26" rx="0" ry="0" width="50" height="6" />
                <rect x="156" y="26" rx="0" ry="0" width="50" height="6" />
                <circle cx="33" cy="69" r="17" />
                <rect x="60" y="65" rx="0" ry="0" width="45" height="6" />
                <rect x="304" y="65" rx="0" ry="0" width="52" height="6" />
                <rect x="16" y="114" rx="0" ry="0" width="340" height="15" />
                <rect x="263" y="208" rx="0" ry="0" width="94" height="19" />
                <rect x="16" y="141" rx="0" ry="0" width="340" height="15" />
                <rect x="16" y="166" rx="0" ry="0" width="340" height="15" />
            </ContentLoader>
        );
    }
    // 渲染评论抽屉
    const renderCommentPopup = () => {
        return (
            <Popup
                className="comment-popup"
                position="bottom"
                visible={commentVisible}
                onMaskClick={onCommentHide}>
                <div className="comment-popup-wrapper">
                    <CommentInput
                        onAddComment={onAddComment}
                        onClose={onCommentHide}
                    />
                </div>
            </Popup>
        );
    };
    // 渲染文章
    const renderArticle = () => {
        return (
            <div className="wrapper" ref={wrapperRef}>
                {/* 文章详情 */}
                <div className="article-wrapper">
                    <div className="header">
                        <h1 className="title">{title}</h1>

                        <div className="info">
                            <span>{pubdate}</span>
                            <span>{read_count} 阅读</span>
                            <span>{comm_count} 评论</span>
                        </div>

                        <div className="author" ref={authorRef}>
                            <img
                                src={
                                    aut_photo ||
                                    "http://geek.itheima.net/images/user_head.jpg"
                                }
                                alt=""
                            />
                            <span className="name">{aut_name}</span>
                            <span
                                onClick={onFollow}
                                className={classNames(
                                    "follow",
                                    is_followed ? "followed" : ""
                                )}>
                                {is_followed ? "已关注" : "关注"}
                            </span>
                        </div>
                    </div>

                    <div className="content">
                        {/* 文章详情 */}
                        <div
                            className="content-html dg-html"
                            // HTML5 中规定：不执行 innerHTML 中的 script 标签
                            // dangerouslySetInnerHTML={{ __html: '<script>alert(1)</script>' }}

                            // 注意：此处图片的 onerror 属性的代码，还是会被执行，不仅影响了用户体验，还会存在 XSS 攻击问题
                            // dangerouslySetInnerHTML={{
                            //   __html: "<img src='x' onerror='alert(1)' />"
                            // }}

                            // 使用 DOMPurify 对 HTML 格式字符串内容进行消毒
                            // dangerouslySetInnerHTML={{
                            //   __html: DOMPurify.sanitize("<img src='x' onerror='alert(1)' />")
                            // }}
                            dangerouslySetInnerHTML={{
                                __html: DOMPurify.sanitize(content),
                            }}
                        />
                        <div className="date">发布文章时间：{pubdate}</div>
                    </div>
                </div>

                {/* 文章评论 */}
                <div className="comment" ref={commentRef}>
                    <div className="comment-header">
                        <span>全部评论（{comm_count}）</span>
                        <span>{like_count} 点赞</span>
                    </div>

                    {/* 评论列表 */}
                    {comments.results.length === 0 ? (
                        <NoneComment />
                    ) : (
                        <div className="comment-list">
                            {comments.results.map((item) => (
                                <CommentItem
                                    onReply={() => onCommentReplyShow(item)}
                                    {...item}
                                    key={item.com_id}
                                    onThumbsUp={() =>
                                        onThumbsUp(item.com_id, item.is_liking)
                                    }
                                />
                            ))}

                            <InfiniteScroll
                                hasMore={hasMore}
                                loadMore={loadMoreComments}
                            />
                        </div>
                    )}
                </div>
            </div>
        );
    };
    // 渲染评论回复的弹出层
    const renderReply = () => {
        return (
            <Popup
                className="reply-popup"
                position="right"
                visible={commentReply.visible}>
                <div className="comment-popup-wrapper">
                    <Reply
                        onClose={onCloseReplyWithUpdate}
                        onReplyThumbsUp={onThumbsUp}
                        art_id={art_id}
                        commentItem={commentReply.commentItem}
                    />
                </div>
            </Popup>
        );
    };
    return (
        <div className={styles.root}>
            <div className="root-wrapper">
                <NavBar
                    onBack={() => history.go(-1)}
                    right={
                        <span>
                            <Icon type="icongengduo" />
                        </span>
                    }>
                    {showNavAuthor && (
                        <div className="nav-author">
                            <img
                                src={
                                    aut_photo ||
                                    "http://geek.itheima.net/images/user_head.jpg"
                                }
                                alt=""
                            />
                            <span className="name">{aut_name}</span>
                            <span
                                onClick={onFollow}
                                className={classNames(
                                    "follow",
                                    true ? "followed" : ""
                                )}>
                                {true ? "已关注" : "关注"}
                            </span>
                        </div>
                    )}
                </NavBar>
                {/* 文章详情和评论 */}
                {renderArticle()}
                {/* 底部评论栏 */}
                <CommentFooter
                    onShowComment={onShowComment}
                    onCollected={onCollected}
                    is_collected={is_collected}
                    onLike={onLike}
                    attitude={attitude}
                    onCommentPopup={onCommentShow}
                />
                // 在 Article 组件的最后，渲染该 Popup 即可
                {renderCommentPopup()}
                {renderReply()}
            </div>
        </div>
    );
};

export default Article;
